home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / telnet.c < prev    next >
C/C++ Source or Header  |  1992-08-19  |  18KB  |  834 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include "config.h"
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "icmp.h"
  8. #include "netuser.h"
  9. #include "tcp.h"
  10. #include "telnet.h"
  11. #include "session.h"
  12. #include "ftp.h"
  13. #include "iface.h"
  14. #include "ax25.h"
  15. #include "lapb.h"
  16. #include "finger.h"
  17. #include "nr4.h"
  18. #ifdef    UNIX
  19. #include <string.h>
  20. #endif
  21.  
  22. #define    CTLZ    26
  23.  
  24. #if !defined( _MEMORY_H) && !defined(_STRING_H)
  25. char *memchr();
  26. #endif
  27.  
  28.  
  29. static free_telnet();
  30. static void answer();
  31. extern char nospace[];
  32. extern char badhost[];
  33. int refuse_echo = 0;
  34. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  35. int debug_options = 0;
  36. extern FILE *trfp;            /* file pointer used for tracing */
  37. void suboption();
  38.  
  39. char *t_options[] = {
  40.     "BINARY", "ECHO", "RCP", "SGA",    "NAMS",    "STATUS", "TM",
  41.     "RCTE", "NAOL", "NAOP", "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", 
  42.     "NAOVTS", "NAOVTD", "NAOLFD", "XASCII", "LOGOUT", "BM", "DET", 
  43.     "SUPDUP", "SUPDUPOUOT", "SNDLOC", "TTYPE", "EOR", "TACACS", 
  44.     "OUTMARK", "LOCNUM", "TN3270", "X3PAD", "NAWS", "TSPEED",
  45.     "LFLOW", "LINEMODE", "XDISPLOC"
  46. };
  47.  
  48. /* Execute user telnet command */
  49. int
  50. dotelnet(argc,argv)
  51. int argc;
  52. char *argv[];   /* argv[1] = host,  argv[2] = service */
  53. {
  54.     void t_state(),rcv_char(),tn_tx();
  55.     char *inet_ntoa();
  56.     int32 resolve();
  57.     int send_tel();
  58.         int unix_send_tel();
  59.     struct session *s;
  60.     struct telnet *tn;
  61.     struct tcb *tcb;
  62.     struct socket lsocket,fsocket;
  63.  
  64.     lsocket.address = ip_addr;
  65.     lsocket.port = lport++;
  66.     printf("Lookup ...");
  67.     if((fsocket.address = resolve(argv[1])) == 0){
  68.         printf(badhost,argv[1]);
  69.         return 1;
  70.     }
  71.     
  72.     if(argc < 3)
  73.         fsocket.port = TELNET_PORT;
  74.     else
  75.         fsocket.port = service_code(argv[2]);
  76.     if(fsocket.port<0){
  77.             printf("Unknown service  %s\n", argv[2]);
  78.         return(1);
  79.           }
  80.     printf(" done. Trying to connect to %s ...\n",
  81.            inet_ntoa( fsocket.address));
  82.     /* Allocate a session descriptor */
  83.     if((s = newsession()) == NULLSESSION){
  84.         printf("Too many sessions\n");
  85.         return 1;
  86.     }
  87.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  88.         strcpy(s->name,argv[1]);
  89.     s->type = TELNET;
  90.     if ((refuse_echo == 0) && (unix_line_mode != 0)) {
  91.         s->parse = unix_send_tel;
  92.     } else {
  93.         s->parse = send_tel;
  94.     }
  95.     current = s;
  96.  
  97.     /* Create and initialize a Telnet protocol descriptor */
  98.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  99.         printf(nospace);
  100.         s->type = FREE;
  101.         return 1;
  102.     }
  103.     tn->session = s;    /* Upward pointer */
  104.     tn->state = TS_DATA;
  105.     s->cb.telnet = tn;    /* Downward pointer */
  106.  
  107.     tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
  108.      rcv_char,tn_tx,t_state,0,(char *)tn);
  109.  
  110.     tn->tcb = tcb;    /* Downward pointer */
  111.     go_mode();
  112.     return 0;
  113. }
  114.  
  115. /* Process typed characters */
  116. int
  117. unix_send_tel(buf,n)
  118. char *buf;
  119. int16 n;
  120. {
  121.     int i;
  122.  
  123.     for (i=0; (i<n) && (buf[i] != '\r'); i++)
  124.         ;
  125.     if (buf[i] == '\r') {
  126.         buf[i] = '\n';
  127.         n = i+1;
  128.     }
  129.     send_tel(buf,n);
  130. }
  131. int
  132. send_tel(buf,n)
  133. char *buf;
  134. int16 n;
  135. {
  136.     struct mbuf *bp;
  137.     if(current == NULLSESSION || current->cb.telnet == NULLTN
  138.      || current->cb.telnet->tcb == NULLTCB)
  139.         return;
  140.     /* If we're doing our own echoing and recording is enabled, record it */
  141.     if(!current->cb.telnet->remote[TN_ECHO] && current->record != NULLFILE)
  142.         fwrite(buf,1,(int)n,current->record);
  143.     bp = qdata(buf,n);
  144.     send_tcp(current->cb.telnet->tcb,bp);
  145. }
  146.  
  147. /* set up correct tty modes */
  148. int
  149. tel_setterm(tn)
  150. register struct telnet *tn;
  151. {
  152.     if(current->cb.telnet->remote[TN_ECHO]) {
  153.         raw();    /* other end is echoing, we're raw */
  154.         if (tn->lflow)
  155.             flowon();
  156.         else
  157.             flowoff();
  158.     } else {
  159.         cooked();
  160.         flowdefault();
  161.     }
  162. }
  163.  
  164. /* 
  165.  * stdio has no way to flush.  So do our own.
  166.  */
  167.  
  168. /* might as well make the buffer big enough for an Ethernet packet */
  169. #define TBSIZE 2048
  170. char termbuf[TBSIZE];
  171. char *termbufp = termbuf;
  172. char *termbufe = termbuf + TBSIZE;
  173.  
  174. int
  175. tnputchar(c)
  176. int c;
  177. {
  178.   if (termbufp >= termbufe) {
  179.     write(1, termbuf, TBSIZE);
  180.     termbufp = termbuf;
  181.   }
  182.   *termbufp++ = c;
  183. }
  184.  
  185. /* send out buffered data */
  186. int
  187. tnflush()
  188. {
  189.   if (termbufp > termbuf)
  190.     write(1, termbuf, termbufp - termbuf);
  191.   termbufp = termbuf;
  192. }
  193.  
  194. /* clear output -- should also do clearout to do Unix clear */
  195. int
  196. tnclear()
  197. {
  198.   termbufp = termbuf;
  199. }
  200.  
  201. /* Process incoming TELNET characters */
  202. int
  203. tel_input(tn,bp)
  204. register struct telnet *tn;
  205. struct mbuf *bp;
  206. {
  207.     char c;
  208.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  209.     FILE *record;
  210.  
  211.  
  212.     /* Optimization for very common special case -- no special chars */
  213.     if(tn->state == TS_DATA){
  214.         while(bp != NULLBUF && memchr(bp->data,IAC,(int)bp->cnt) == NULLCHAR){
  215.             if (! tn->outsup) {
  216.                 if((record = tn->session->record) != NULLFILE)
  217.                     fwrite(bp->data,1,(int)bp->cnt,record);
  218.                 while(bp->cnt-- != 0)
  219.                     tnputchar(*bp->data++);
  220.             }
  221.             bp = free_mbuf(bp);
  222.         }
  223.     }
  224.     while(pullup(&bp,&c,1) == 1){
  225.         switch(tn->state){
  226.         case TS_DATA:
  227.             if(uchar(c) == IAC){
  228.                 tn->state = TS_IAC;
  229.             } else {
  230. #ifdef undef
  231.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  232.                     c &= 0x7f;
  233. #endif
  234.                 if (! tn->outsup) {
  235.                     tnputchar(c);
  236.                     if((record = tn->session->record) 
  237.                        != NULLFILE)
  238.                         putc(c,record);
  239.                 }
  240.             }
  241.             break;
  242.         case TS_IAC:
  243. process_iac:
  244.             switch(uchar(c)){
  245.             case WILL:
  246.                 tn->state = TS_WILL;
  247.                 break;
  248.             case WONT:
  249.                 tn->state = TS_WONT;
  250.                 break;
  251.             case DO:
  252.                 tn->state = TS_DO;
  253.                 break;
  254.             case DONT:
  255.                 tn->state = TS_DONT;
  256.                 break;
  257.             case TN_DM:
  258.                 /*
  259.                  * if outsup > 1, we are still in urgent
  260.                  * data, so DM is ignored
  261.                  */
  262.                 if (tn->outsup == 1) {
  263.                     tn->outsup = 0;
  264.                     if (debug_options)
  265.                         fprintf(trfp, "[End of urgent data]\n");
  266.                 }
  267.                 tn->state = TS_DATA;
  268.                 break;
  269.             case SB:
  270.                 SB_CLEAR();
  271.                 tn->state = TS_SB;
  272.                 break;
  273.             case IAC:
  274.                 tnputchar(c);
  275.                 tn->state = TS_DATA;
  276.                 break;
  277.             default:
  278.                 tn->state = TS_DATA;
  279.                 break;
  280.             }
  281.             break;
  282.         case TS_WILL:
  283.             willopt(tn,c);
  284.             tn->state = TS_DATA;
  285.             break;
  286.         case TS_WONT:
  287.             wontopt(tn,c);
  288.             tn->state = TS_DATA;
  289.             break;
  290.         case TS_DO:
  291.             doopt(tn,c);
  292.             tn->state = TS_DATA;
  293.             break;
  294.         case TS_DONT:
  295.             dontopt(tn,c);
  296.             tn->state = TS_DATA;
  297.             break;
  298.             case TS_SB:
  299.             if (uchar(c) == IAC) {
  300.                 tn->state = TS_SE;
  301.                 break;
  302.             } else {
  303.                 SB_ACCUM(c);
  304.             }
  305.             break;
  306.         case TS_SE:
  307.             if (uchar(c) != SE) {
  308.               if (uchar(c) != IAC) {
  309.                 /*
  310.                  * This is an error.  We only expect to get
  311.                  * "IAC IAC" or "IAC SE".  Several things may
  312.                  * have happend.  An IAC was not doubled, the
  313.                  * IAC SE was left off, or another option got
  314.                  * inserted into the suboption are all possibilities.
  315.                  * If we assume that the IAC was not doubled,
  316.                  * and really the IAC SE was left off, we could
  317.                  * get into an infinate loop here.  So, instead,
  318.                  * we terminate the suboption, and process the
  319.                  * partial suboption if we can.
  320.                  */
  321.                 SB_ACCUM(IAC);
  322.                 SB_ACCUM(c);
  323.                 tn->subpointer -= 2;
  324.                 SB_TERM();
  325.                 suboption(tn);    /* handle sub-option */
  326.                 tn->state = TS_IAC;
  327.                 goto process_iac;
  328.               }
  329.               SB_ACCUM(c);
  330.               tn->state = TS_SB;
  331.             } else {
  332.               SB_ACCUM(IAC);
  333.               SB_ACCUM(SE);
  334.               tn->subpointer -= 2;
  335.               SB_TERM();
  336.               suboption(tn);    /* handle sub-option */
  337.               tn->state = TS_DATA;
  338.             }
  339.             break;
  340.         }
  341.     }
  342. }
  343.  
  344. /* Telnet receiver upcall routine */
  345. void
  346. rcv_char(tcb,cnt)
  347. register struct tcb *tcb;
  348. int16 cnt;
  349. {
  350.     struct mbuf *bp;
  351.     struct telnet *tn;
  352.     FILE *record;
  353. #ifdef    FLOW
  354.     extern int ttyflow;
  355. #endif
  356.     if((tn = (struct telnet *)tcb->user) == NULLTN){
  357.         /* Unknown connection; ignore it */
  358.         return;
  359.     }
  360.     /* Hold output if we're not the current session */
  361.     if(mode != CONV_MODE || current == NULLSESSION
  362. #ifdef    FLOW
  363.      || !ttyflow    /* Or if blocked by keyboard input -- hyc */
  364. #endif
  365.      || current->type != TELNET || current->cb.telnet != tn)
  366.         return;
  367.  
  368. /*
  369.  * Urgent data is done by combination of the TCP level and this code.
  370.  * The TCP level sets URGCUR and tcb->up (urgent pointer), but we
  371.  * clear it at this level.  We want to clear it when we've taken
  372.  * data beyond the urgent pointer, and only here are we in a position
  373.  * to control that.  The code is better here anyway, because other
  374.  * applications may treat the urgent pointer differently